package com.compass.mobile.ui.activity

import LogUtil
import UserInfoManager
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.KeyEvent
import android.view.View
import android.view.View.OnKeyListener
import android.view.inputmethod.EditorInfo
import androidx.activity.viewModels
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.leanback.widget.ArrayObjectAdapter
import androidx.leanback.widget.BaseGridView
import androidx.leanback.widget.FocusHighlight
import androidx.leanback.widget.FocusHighlightHelper
import androidx.leanback.widget.OnChildViewHolderSelectedListener
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.compass.mobile.callback.OnItemClickListener
import com.compass.mobile.databinding.ActivityRecommendDoctorBinding
import com.compass.mobile.framework.base.BaseVBActivity
import com.compass.mobile.framework.constant.CANCEL_INVITE
import com.compass.mobile.framework.constant.CLOSE_EVENT
import com.compass.mobile.framework.constant.PATIENT_ID
import com.compass.mobile.framework.ext.gone
import com.compass.mobile.framework.ext.textChangeFlow
import com.compass.mobile.framework.ext.visible
import com.compass.mobile.framework.ifly.IFlyHelper
import com.compass.mobile.framework.ifly.IFlyOptCallback
import com.compass.mobile.framework.utils.LiveDataBus
import com.compass.mobile.framework.utils.dpToPx
import com.compass.mobile.framework.utils.getAction
import com.compass.mobile.models.Dictionaries
import com.compass.mobile.models.Doctor
import com.compass.mobile.models.MessageModel
import com.compass.mobile.models.PatientBean
import com.compass.mobile.presenters.DoctorPresenter
import com.compass.mobile.ui.viewModel.DoctorViewModel
import com.compass.mobile.ui.viewModel.MainViewModel
import com.compass.mobile.ui.viewModel.UserViewModel
import com.compass.mobile.widget.MyBridgeAdapter
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import com.google.gson.reflect.TypeToken
import com.netease.nimlib.sdk.NIMClient
import com.netease.nimlib.sdk.Observer
import com.netease.nimlib.sdk.RequestCallback
import com.netease.nimlib.sdk.auth.AuthService
import com.netease.nimlib.sdk.auth.LoginInfo
import com.netease.nimlib.sdk.avsignalling.SignallingServiceObserver
import com.netease.nimlib.sdk.avsignalling.constant.SignallingEventType
import com.netease.nimlib.sdk.avsignalling.event.CanceledInviteEvent
import com.netease.nimlib.sdk.avsignalling.event.ChannelCloseEvent
import com.netease.nimlib.sdk.avsignalling.event.ChannelCommonEvent
import com.netease.nimlib.sdk.avsignalling.event.ControlEvent
import com.netease.nimlib.sdk.avsignalling.event.InviteAckEvent
import com.netease.nimlib.sdk.avsignalling.event.InvitedEvent
import com.netease.nimlib.sdk.avsignalling.event.UserJoinEvent
import com.netease.nimlib.sdk.avsignalling.event.UserLeaveEvent
import com.netease.nimlib.sdk.msg.MsgServiceObserve
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import toBeanOrNull
import toJson

/**
 * Description： 推荐医生（村医列表 暂定）
 * Date:2024/6/29 14:10
 */
class RecommendedDoctorActivity : BaseVBActivity<ActivityRecommendDoctorBinding>() {

    companion object {
        fun start(context: Context,comeType:Int?) {
            val intent = Intent(context, RecommendedDoctorActivity::class.java)
            intent.putExtra("comeType", comeType)
            context.startActivity(intent)
        }
    }
    var tag = "VideoCall:===onlineObserver"
    private var keyWords: String? = null
    private val doctorViewModel: DoctorViewModel by viewModels()
    private var doctors: MutableList<Doctor> = mutableListOf()
    private lateinit var arrayObjectAdapter: ArrayObjectAdapter
    private var isFirst = true
    private val mainViewModel: MainViewModel by viewModels()
    private val userViewModel: UserViewModel by viewModels()
    private var comeType: Int = 0//1为图文，2电话，3视频
    override fun initView(savedInstanceState: Bundle?) {
        comeType = intent.getIntExtra("comeType",0)
        initSpecialColumn()
        mBinding.edtKeyWords.setOnEditorActionListener { _, actionId, _ ->
            if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                //点击了搜索按钮后，需要隐藏软键盘
                keyWords = mBinding.edtKeyWords.text.toString().trim()
                getDoctor()

            }
            false
        }


        mBinding.edtKeyWords.textChangeFlow()
            .distinctUntilChanged()
            .debounce(500)
            .flowOn(Dispatchers.IO)
            .onEach {
                //这里走查询接口
                keyWords = mBinding.edtKeyWords.text.toString().trim()
                getDoctor()
            }
            .launchIn(lifecycleScope)

    }


    private fun getDoctor() {
        if (keyWords.isNullOrEmpty() && !isFirst) {
            setDoctor(UserInfoManager.getAllDoctor()?.toBeanOrNull<MutableList<Doctor>>())
        } else {
            doctorViewModel.searchDoctors(keyWords,comeType)
        }
    }

    /**
     * 登录IM
     */
    private fun doLoginIM(patientBean: PatientBean) {
        val info = LoginInfo(patientBean.wyyxAccId, patientBean.wyyxToken)
        val callback: RequestCallback<LoginInfo?> = object : RequestCallback<LoginInfo?> {
            override fun onSuccess(param: LoginInfo?) {

                UserInfoManager.putString(PATIENT_ID,patientBean.id)
                UserInfoManager.saveImUserAccount(param?.account)
                UserInfoManager.saveImToken(param?.token)
//                showToast("就诊人登录成功")
            }

            override fun onFailed(code: Int) {


            }

            override fun onException(exception: Throwable) {

            }
        }
        //执行手动登录
        NIMClient.getService(AuthService::class.java).login(info).setCallback(callback)

    }

    private var onlineObserver: Observer<ChannelCommonEvent>? = null
    override fun initData() {
        showLoading()
        getDoctor()
        mainViewModel.getAllDictionaries()
        mainViewModel.getDefPatient()
        userViewModel.gePatients()
        userViewModel.patientLiveData.observe(this) {
            it?.let { list ->
                UserInfoManager.savePatientList(list.toJson())
            }
            dismissLoading()
        }
        mainViewModel.patientDefLiveData.observe(this) {
            it?.let { bean ->
                UserInfoManager.savePatientInfo(bean.toJson())
                doLoginIM(bean)
                mBinding.topView.setDefaultPatientInfo()

            } ?: kotlin.run {
                UserInfoManager.savePatientInfo(null)
                mBinding.topView.setDefaultPatientInfo()
            }
        }
        mainViewModel.allDictionariesLiveData.observe(this) {
            it?.let { warp ->
                UserInfoManager.saveNotificationType(warp.patient_with_treatment_system_messages_type.toJson())
                UserInfoManager.saveOrderType(warp.order_consultation_status.toJson())
                UserInfoManager.saveOrderConsultationType(warp.order_consultation_type.toJson())
                UserInfoManager.saveInspectionReportType(warp.inspection_report_type.toJson())
                UserInfoManager.saveOrderNurseStatusType(warp.order_nurse_status.toJson())
                UserInfoManager.saveInspectionType(warp.order_inspection_status.toJson())
//                UserInfoManager.saveSuggestType(warp.complaint_suggest_detail_type.toJson())
            }
        }
        doctorViewModel.doctorsLiveData.observe(this) {
            dismissLoading()
            arrayObjectAdapter.clear()
            if (isFirst) {
                isFirst = false //第一缓存全部医生数据
                UserInfoManager.saveAllDoctorType(it?.toJson())
            }
            setDoctor(it)
        }

        GlobalScope.launch(Dispatchers.Main) {
            delay(1000)
            IFlyHelper.initIFly(this@RecommendedDoctorActivity,flyCallback)
        }

        // 在线通知事件观察者
        onlineObserver = Observer<ChannelCommonEvent> { event: ChannelCommonEvent? ->

            when (event?.eventType) {
                SignallingEventType.CLOSE -> {
                    var channelCloseEvent = event as ChannelCloseEvent

                    LiveDataBus.get().with(CLOSE_EVENT).postValue(channelCloseEvent.channelBaseInfo)
                    LogUtil.d(
                        "频道关闭事件 channelCloseEvent==${channelCloseEvent.toJson()}",
                        tag = tag
                    )
                }

                SignallingEventType.UN_KNOW -> {
                    LogUtil.d("未知事件", tag = tag)
                }

                SignallingEventType.JOIN -> {
                    var userJoinEvent = event as UserJoinEvent

                    LogUtil.d(
                        "有人加入频道事件 userJoinEvent==${userJoinEvent.toJson()}",
                        tag = tag
                    )
                }

                SignallingEventType.INVITE -> {
                    var inviteEvent = event as InvitedEvent

                    //收到邀请
                    VideoAnswerActivity.start(this, inviteEvent)
                    LogUtil.d("被邀请事件  inviteEvent==${inviteEvent.toJson()}", tag = tag)
//                    LogUtil.d("被邀请事件  fromAccountId==${inviteEvent.fromAccountId}", tag = tag)
                }

                SignallingEventType.CANCEL_INVITE -> {
                    var canceledInviteEvent = event as CanceledInviteEvent
                    LiveDataBus.get().with(CANCEL_INVITE).postValue(canceledInviteEvent.channelBaseInfo)
                    LogUtil.d(
                        "取消邀请事件 canceledInviteEvent==${canceledInviteEvent.toJson()}",
                        tag = tag
                    )
                }

                SignallingEventType.REJECT, SignallingEventType.ACCEPT -> {
                    var inviteAckEvent = event as InviteAckEvent


                    LogUtil.d(
                        "对方拒绝/接受 邀请事件 inviteAckEvent===${inviteAckEvent.toJson()}",
                        tag = tag
                    )
                }

                SignallingEventType.LEAVE -> {
                    var userLeaveEvent = event as UserLeaveEvent
                    LogUtil.d(
                        "有用户离开频道事件  userLeaveEvent==${userLeaveEvent.toJson()}",
                        tag = tag
                    )
                }

                SignallingEventType.CONTROL -> {
                    var controlEvent = event as ControlEvent
                    LogUtil.d(
                        "自定义控制命令事件  controlEvent==${controlEvent.toJson()}",
                        tag = tag
                    )
                }

                else -> {
                    LogUtil.d("未知事件", tag = tag)
                }
            }

        }
        NIMClient.getService(SignallingServiceObserver::class.java)
            .observeOnlineNotification(onlineObserver, true)
        initCustomNotification()

    }
    /**
     * 注册云信自定义通知
     */
    private fun initCustomNotification() {
        NIMClient.getService(MsgServiceObserve::class.java).observeCustomNotification({

//                            LogUtil.d("接收到自定义通知：${it.toJson()}" )
            val type = object : TypeToken<MessageModel>() {}.type
            try {
                val messageModel: MessageModel = Gson().fromJson(it.content, type)
//                LogUtil.d("接收到自定义通知：${messageModel.toJson()}" )
                LogUtil.d("消息通知 type===${messageModel.toJson()}")
                messageModel.messageType?.let { type->
//                    initNoticeOfDisposition(getAction(type),messageModel.attach)
                    LiveDataBus.get().with(getAction(type)).postValue(messageModel.attach)
                }
            } catch (e: JsonSyntaxException) {
                e.printStackTrace()
            }

        }, true)

    }


    private val flyCallback = object : IFlyOptCallback {
        override fun onSuccess(text: String?) {
            IFlyHelper.getText(this@RecommendedDoctorActivity,textCallback)
//            mBinding.edtKeyWords.requestFocus()
        }

        override fun onFail(code: Int, text: String?) {
        }
    }
    private val textCallback = object : IFlyOptCallback {
        override fun onSuccess(text: String?){
            text.let {
                mBinding.edtKeyWords.setText(it)
                mBinding.edtKeyWords.text?.let { it1 -> mBinding.edtKeyWords.setSelection(it1.length) }
            }
        }

        override fun onFail(code: Int, text: String?) {
        }
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        LogUtil.d("action===${event?.action}  ----isMoveTop===$isMoveTop")
        if (event?.action == KeyEvent.ACTION_UP && isMoveTop) {
            mBinding.edtKeyWords.requestFocus()
        }
        return super.onKeyDown(keyCode, event)
    }
    private fun setDoctor(list: MutableList<Doctor>?) {

        if (list.isNullOrEmpty()) {
            mBinding.emptyView.visible()
        } else {
            mBinding.emptyView.gone()
            doctors = list
            arrayObjectAdapter.addAll(0, doctors)
        }
    }


    private val onItemClickListener: OnItemClickListener = object : OnItemClickListener {
        override fun onItemClick(position: Int, view: View) {
            val item = doctors[position]


            item.department?.let {
                DoctorHomePageActivity.start(this@RecommendedDoctorActivity, item.id, it)
            }


        }
    }


    @SuppressLint("RestrictedApi")
    fun initSpecialColumn() {
        mBinding.caseItem.setNumColumns(2)
        mBinding.caseItem.horizontalSpacing = dpToPx(10)
        mBinding.caseItem.verticalSpacing = dpToPx(10)
        val departmentIntroductionPresenter = DoctorPresenter("2")
        arrayObjectAdapter = ArrayObjectAdapter(departmentIntroductionPresenter)
        val itemBridgeAdapter = MyBridgeAdapter(
            this,
            arrayObjectAdapter, onItemClickListener
        )
        mBinding.caseItem?.setOnChildViewHolderSelectedListener(onChildViewHolderSelectedListener)
        mBinding.caseItem.setAdapter(itemBridgeAdapter)
        mBinding.caseItem.setFocusScrollStrategy(BaseGridView.FOCUS_SCROLL_ITEM)
        arrayObjectAdapter.addAll(0, doctors)
        FocusHighlightHelper.setupBrowseItemFocusHighlight(
            itemBridgeAdapter,
            FocusHighlight.ZOOM_FACTOR_NONE, false
        )
        mBinding.caseItem.requestFocus()
    }

    private var isMoveTop = true
    private val onChildViewHolderSelectedListener: OnChildViewHolderSelectedListener = object :
        OnChildViewHolderSelectedListener() {
        override fun onChildViewHolderSelected(
            parent: RecyclerView?,
            child: RecyclerView.ViewHolder?,
            position: Int,
            subposition: Int
        ) {
            if (position < 3) {
                isMoveTop = true
            } else {
                isMoveTop = false
            }
        }
    }





    override fun onDestroy() {
        super.onDestroy()
        NIMClient.getService(SignallingServiceObserver::class.java)
            .observeOnlineNotification(onlineObserver, false)
        IFlyHelper.unInitIFly()
    }

}